1 /*
2  * Collie - An asynchronous event-driven network framework using Dlang development
3  *
4  * Copyright (C) 2015-2017  Shanghai Putao Technology Co., Ltd 
5  *
6  * Developer: putao's Dlang team
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 module collie.channel.handlercontext;
12 
13 import std.conv;
14 import std.functional;
15 import kiss.logger;
16 import collie.channel.pipeline;
17 import collie.channel.handler;
18 import collie.channel.exception;
19 import collie.net;
20 import kiss.event.socket;
21 
22 interface HandlerContext(In, Out)
23 {
24     alias HandlerTheCallBack = void delegate(Out, size_t);
25 
26     void fireRead(In msg);
27 
28     void fireTimeOut();
29 
30     void fireTransportActive();
31     void fireTransportInactive();
32 
33     void fireWrite(Out msg, HandlerTheCallBack cback = null);
34     void fireClose();
35 
36     @property PipelineBase pipeline();
37 
38     @property Channel transport();
39 
40 }
41 
42 interface InboundHandlerContext(In)
43 {
44     void fireRead(In msg);
45     void fireTimeOut();
46 
47     void fireTransportActive();
48     void fireTransportInactive();
49 
50     @property PipelineBase pipeline();
51 
52     @property Channel transport();
53 }
54 
55 interface OutboundHandlerContext(Out)
56 {
57 	alias OutboundTheCallBack = void delegate(Out, size_t);
58 
59     void fireWrite(Out msg, OutboundTheCallBack cback = null);
60     void fireClose();
61 
62     @property PipelineBase pipeline();
63 
64     @property Channel transport();
65 }
66 
67 enum HandlerDir
68 {
69     IN,
70     OUT,
71     BOTH
72 }
73 
74 class ContextImplBase(H, Context) : PipelineContext
75 {
76     ~this()
77     {
78     }
79 
80     pragma(inline,true)
81     final @property auto handler()
82     {
83         return _handler;
84     }
85 
86     pragma(inline,true)
87     final void initialize(PipelineBase pipeline, H handler)
88     {
89         _pipeline = pipeline;
90         _handler = handler;
91     }
92 
93     // PipelineContext overrides
94 
95     final override void attachPipeline()
96     {
97         if (!_attached)
98         {
99             attachContext(_handler, _impl);
100             _handler.attachPipeline(_impl);
101             _attached = true;
102         }
103     }
104 
105     final override void detachPipeline()
106     {
107         _handler.detachPipeline(_impl);
108         _attached = false;
109         _pipeline = null;
110     }
111 
112     final override void setNextIn(PipelineContext ctx)
113     {
114         if (!ctx)
115         {
116             _nextIn = null;
117             return;
118         }
119         auto nextIn = cast(InboundLink!(H.rout))(ctx);
120         if (nextIn)
121         {
122             _nextIn = nextIn;
123         }
124         else
125         {
126 			throw new InBoundTypeException("inbound type mismatch after ");
127         }
128     }
129 
130     final override void setNextOut(PipelineContext ctx)
131     {
132         if (!ctx)
133         {
134             _nextOut = null;
135             return;
136         }
137         auto nextOut = cast(OutboundLink!(H.wout))(ctx);
138         if (nextOut)
139         {
140             _nextOut = nextOut;
141         }
142         else
143         {
144 			throw new OutBoundTypeException("outbound type mismatch after ");
145         }
146     }
147 
148     pragma(inline)
149     final override HandlerDir getDirection()
150     {
151         return H.dir;
152     }
153 
154 protected:
155     Context _impl;
156     PipelineBase _pipeline;
157     H _handler;
158     InboundLink!(H.rout) _nextIn = null;
159     OutboundLink!(H.wout) _nextOut = null;
160 
161 private:
162     bool _attached = false;
163 }
164 
165 mixin template CommonContextImpl()
166 {
167     alias Rin = H.rin;
168     alias Rout = H.rout;
169     alias Win = H.win;
170     alias Wout = H.wout;
171 
172     this(PipelineBase pipeline, H handler)
173     {
174         _impl = this;
175         initialize(pipeline, handler);
176     }
177 
178     // For StaticPipeline
179     this()
180     {
181         _impl = this;
182     }
183 
184     pragma(inline)
185     final override @property  Channel transport()
186     {
187         return _pipeline is null ? null : pipeline.transport();
188     }
189 
190     pragma(inline)
191     final override @property PipelineBase pipeline()
192     {
193         return _pipeline;
194     }
195 }
196 
197 mixin template ReadContextImpl()
198 {
199 
200     override void fireRead(Rout msg)
201     {
202         if (this._nextIn)
203         {
204             this._nextIn.read(msg);
205         }
206         else
207         {
208             logInfo("read reached end of pipeline");
209         }
210     }
211 
212     override void fireTimeOut()
213     {
214         if (this._nextIn)
215         {
216             this._nextIn.timeOut();
217         }
218     }
219 
220     override void fireTransportActive()
221     {
222         if (this._nextIn)
223         {
224             this._nextIn.transportActive();
225         }
226     }
227 
228     override void fireTransportInactive()
229     {
230         if (this._nextIn)
231         {
232             this._nextIn.transportInactive();
233         }
234     }
235 
236     // InboundLink overrides
237     override void read(Rin msg)
238     {
239         _handler.read(this, (msg));
240     }
241 
242     override void timeOut()
243     {
244         this._handler.timeOut(this);
245     }
246 
247     override void transportActive()
248     {
249         this._handler.transportActive(this);
250     }
251 
252     override void transportInactive()
253     {
254         _handler.transportInactive(this);
255     }
256 }
257 
258 mixin template WriteContextImpl()
259 {
260 	alias NextCallBack = void delegate(Wout, size_t);
261 
262     pragma(inline)
263     override void fireWrite(Wout msg, NextCallBack cback = null)
264     {
265         if (_nextOut)
266         {
267             _nextOut.write(msg, cback);
268         }
269         else
270         {
271             logInfo("write reached end of pipeline");
272 			if(cback !is null)
273 				cback(msg,0);
274         }
275     }
276 
277     pragma(inline)
278     override void fireClose()
279     {
280         if (_nextOut)
281         {
282             _nextOut.close();
283         }
284         else
285         {
286             logInfo("close reached end of pipeline");
287         }
288     }
289 
290     // OutboundLink overrides
291 	alias ThisCallBack = void delegate(Win, size_t);
292     pragma(inline)
293     override void write(Win msg, ThisCallBack cback = null)
294     {
295         _handler.write(this, msg, cback);
296     }
297 
298     pragma(inline)
299     override void close()
300     {
301         _handler.close(this);
302     }
303 
304 }
305 
306 final class ContextImpl(H) : ContextImplBase!(H, HandlerContext!(H.rout,
307     H.wout)), HandlerContext!(H.rout, H.wout), InboundLink!(H.rin), OutboundLink!(H.win)
308 {
309 
310     static enum dir = HandlerDir.BOTH;
311 
312     mixin CommonContextImpl;
313 
314     mixin WriteContextImpl;
315 
316     mixin ReadContextImpl;
317 
318 }
319 
320 final class InboundContextImpl(H) : ContextImplBase!(H,
321     InboundHandlerContext!(H.rout)), InboundHandlerContext!(H.rout), InboundLink!(H.rin)
322 {
323     static enum dir = HandlerDir.IN;
324 
325     mixin CommonContextImpl;
326 
327     mixin ReadContextImpl;
328 
329 }
330 
331 final class OutboundContextImpl(H) : ContextImplBase!(H,
332     OutboundHandlerContext!(H.wout)), OutboundHandlerContext!(H.wout), OutboundLink!(H.win)
333 {
334 
335     static enum dir = HandlerDir.OUT;
336 
337     mixin CommonContextImpl;
338 
339     mixin WriteContextImpl;
340 }
341 
342 template ContextType(H)
343 {
344     static if (H.dir == HandlerDir.BOTH)
345         alias ContextType = ContextImpl!(H);
346     else static if (H.dir == HandlerDir.IN)
347         alias ContextType = InboundContextImpl!(H);
348     else
349         alias ContextType = OutboundContextImpl!(H);
350 }